/**
 * This file is a part of qloudgen-rul. 
 * You can redistribute qloudgen-rul and/or modify it under the terms of the Lesser GNU General Public License version 3. 
 * qloudgen-rul is distributed WITHOUT ANY WARRANTY. 
 *
 * See the Lesser GNU General Public License for more details at http://www.gnu.org/licenses/. 
 **/
package org.qloudgen.rul.drools.rule;

import java.util.Set;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.builder.KieScanner;
import org.drools.compiler.kie.builder.impl.KieContainerImpl;

import org.qloudgen.rul.drools.kie.DroolsKieServicesImpl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>Title: Drools Implementation</p>
 * <p>Description: Wrappered jboss drools rules engine with maven implementation.</p>
 * <p>Copyright: qloudgen/rul 2014</p>
 * @author <a href="mailto:hyq.dd.sun@gmail.com">glue.3M</a>
 */
public abstract class AbstractDroolsMavenRuleRunner extends AbstractDroolsRuleRunner {
	/**
	 * Log output.
	 */
	private final static Logger logger = LoggerFactory.getLogger( AbstractDroolsMavenRuleRunner.class );
	/**
	 *
	 */
	//private KieServices services = KieServices.Factory.get();
	private KieServices services = new DroolsKieServicesImpl();
	/**
	 *
	 */
	private ConcurrentMap<DroolsReleaseId,KieContainer> containers = new ConcurrentHashMap<DroolsReleaseId,KieContainer>();
	/**
	 *
	 */
	private ConcurrentMap<DroolsReleaseId,KieScanner> scanners = new ConcurrentHashMap<DroolsReleaseId,KieScanner>();
	/**
	 *
	 */
	private List<DroolsReleaseId> releaseIdList = null;
	
	/**
	 * Default constructor.
	 */
	public AbstractDroolsMavenRuleRunner() {
	}
	
	/**
	 * Sets current release id list.
	 *
	 * @param releaseIdList
	 */
	public void setReleaseIdList(final List<DroolsReleaseId> releaseIdList) {
		this.releaseIdList = releaseIdList;
	}
	
	/**
	 * Initialize.
	 */
	public void init() {
		logger.info( "Starting initialize rule runner...{}" , releaseIdList.size() );
		//
		for ( DroolsReleaseId releaseId : releaseIdList ) {
			/**
			 * Create kie container by release id.
			 */
			KieContainer container = services.newKieContainer( services.newReleaseId( releaseId.getGroupId() , releaseId.getArtifactId() , releaseId.getVersion() ) );
			/**
			 * Create kie scanner by container.
			 */
			KieScanner scanner = services.newKieScanner( container );
			/**
			 * Add kie container & scanner.
			 */
			containers.put( releaseId , container );
			scanners.put( releaseId , scanner );
			//
			logger.trace( "Current added release id is...{}" , releaseId );
			logger.trace( "Current added container is...{}" , container );
			logger.trace( "Current added scanner is...{}" , scanner );
			//
			initInternal( scanner );
		}
		//
		logger.info( "Started initialize rule runner...{}" , releaseIdList.size() );
	}
	
	/**
	 * Initialize current scanner.
	 *
	 * @param scanner
	 */
	protected abstract void initInternal(KieScanner scanner);
	
	/**
	 * Destroy.
	 */
	public void destroy() {
		if ( releaseIdList == null ) {
			return;
		}
		logger.info( "Starting destroy rule runner...{}" , releaseIdList.size() );
		//
		for ( DroolsReleaseId releaseId : releaseIdList ) {
			KieContainer container = containers.remove( releaseId );
			KieScanner scanner = scanners.remove( releaseId );
			//
			logger.trace( "Current removed release id is...{}" , releaseId );
			logger.trace( "Current removed container is...{}" , container );
			logger.trace( "Current removed scanner is...{}" , scanner );
			//
			destroyInternal( scanner );
			/**
			 * Force to null.
			 */
			scanner = null;
			container = null;
		}
		releaseIdList = null;
		//
		logger.info( "Started destroy rule runner..." );
	}
	
	/**
	 * Destroy current scanner.
	 *
	 * @param scanner
	 */
	protected abstract void destroyInternal(KieScanner scanner);
	
	/**
	 * Returns current container by session name.
	 *
	 * Session name must be unique in all kmodule.xml
	 *
	 * @param sessionName
	 * @return KieContainer
	 */
	protected KieContainer getContainer(String sessionName) {
		//
		Set<DroolsReleaseId> releaseIds = containers.keySet();
		for ( DroolsReleaseId releaseId : releaseIds ) {
			KieContainer container = containers.get( releaseId );
			if ( ( ( KieContainerImpl )container ).getKieSessionModel( sessionName ) != null ) {
				logger.trace( "Current found release id is...{}" , releaseId );
				logger.trace( "Current found container is...{}" , container );
				//
				return container;
			}
		}
		//
		throw new DroolsException( "Current found container is null by...".concat( sessionName ) );
	}
	
	/**
	 * Returns current scanner by release id.
	 *
	 * @param releaseId
	 * @return KieScanner
	 */
	protected KieScanner getScanner(DroolsReleaseId releaseId) {
		return scanners.get( releaseId );
	}
	
	/**
	 * Returns the String representation.
	 *
	 * @return String
	 */
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append( "[" );
		builder.append( super.toString() );
		builder.append( "-->" );
		builder.append( "services=" ).append( services ).append( "," );
		builder.append( "containers=" ).append( containers ).append( "," );
		builder.append( "scanners=" ).append( scanners );
		builder.append( "]" );
		//
		return builder.toString();
	}
}